import java.util.Random;
import org.jcsp.lang.*;
import org.jcsp.plugNplay.ints.*;

class Philosopher implements CSProcess {

  protected final static int seconds = 1000;

  protected final static int maxThink = 10*seconds;
  protected final static int maxEat = 15*seconds;

  protected final int id;
  protected final ChannelOutputInt left, right, down, up;
  protected final PhilReport report;

  protected final Random random;

  public Philosopher (int id, ChannelOutputInt left, ChannelOutputInt right,
                      ChannelOutputInt down, ChannelOutputInt up,
                      PhilReport report) {
    this.id = id;
    this.left = left;
    this.right = right;
    this.down = down;
    this.up = up;
    this.report = report;
    this.random = new Random (id + 1);
  }


  public void run () {

    final CSTimer tim = new CSTimer ();

    final ProcessWriteInt signalLeft = new ProcessWriteInt (left);
    signalLeft.value = id;

    final ProcessWriteInt signalRight = new ProcessWriteInt (right);
    signalRight.value = id;

    final CSProcess signalForks = new Parallel (new CSProcess[] {signalLeft, signalRight});

    while (true) {
      report.thinking (id);
      tim.sleep (range (maxThink));    // Philosopher is thinking
      report.hungry (id);
      down.write (id);                 // get past the security guard
      report.sitting (id);
      signalForks.run ();              // pick up my forks 
      report.eating (id);
      tim.sleep (range (maxEat));      // Philosopher is eating
      report.leaving (id);
      signalForks.run ();              // put down my forks 
      up.write (id);                   // get up from the table and go past the security guard
    }
  }

  protected int range (int n) {
    int i = random.nextInt ();
    if (i < 0) {
      if (i == Integer.MIN_VALUE) {
        i = 42;
      } else {
        i = -i;
      }
    }
    return i % n;
  }

}
